﻿using System.Collections;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace ZeroSum.Extensions;

/// <summary>
///     Type类型扩展
/// </summary>
public static class Extensions
{
    /// <summary>
    ///     判断类型是否为Nullable类型
    /// </summary>
    /// <param name="type"> 要处理的类型 </param>
    /// <returns> 是返回True，不是返回False </returns>
    public static bool IsNullableType(this Type type)
    {
        return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

    /// <summary>
    ///     返回当前方法信息是否是重写方法
    /// </summary>
    /// <param name="method">要判断的方法信息</param>
    /// <returns>是否是重写方法</returns>
    public static bool IsOverridden(this MethodInfo method)
    {
        return method.GetBaseDefinition().DeclaringType != method.DeclaringType;
    }

    /// <summary>
    ///     从类型成员获取指定Attribute特性
    /// </summary>
    /// <typeparam name="T">Attribute特性类型</typeparam>
    /// <param name="memberInfo">类型类型成员</param>
    /// <param name="inherit">是否从继承中查找</param>
    /// <returns>返回所有指定Attribute特性的数组</returns>
    public static T[] GetAttributes<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute
    {
        return memberInfo.GetCustomAttributes(typeof(T), inherit).Cast<T>().ToArray();
    }

    /// <summary>
    ///     判断当前类型是否可由指定类型派生
    /// </summary>
    public static bool IsDeriveClassFrom<TBaseType>(this Type type, bool canAbstract = false)
    {
        return IsDeriveClassFrom(type, typeof(TBaseType), canAbstract);
    }

    /// <summary>
    ///     判断当前类型是否可由指定类型派生
    /// </summary>
    public static bool IsDeriveClassFrom(this Type type, Type baseType, bool canAbstract = false)
    {
        return type.IsClass && !canAbstract && !type.IsAbstract && type.IsBaseOn(baseType);
    }


    /// <summary>
    ///     返回当前类型是否是指定基类的派生类
    /// </summary>
    /// <typeparam name="BaseType">要判断的基类型</typeparam>
    /// <param name="type">当前类型</param>
    /// <returns></returns>
    public static bool IsBaseOn<BaseType>(this Type type)
    {
        return type.IsBaseOn(typeof(BaseType));
    }

    /// <summary>
    ///     返回当前类型是否是指定基类的派生类
    /// </summary>
    /// <param name="type">当前类型</param>
    /// <param name="baseType">要判断的基类型</param>
    /// <returns></returns>
    public static bool IsBaseOn(this Type type, Type baseType)
    {
        if (baseType.IsGenericTypeDefinition) return baseType.IsGenericAssignableFrom(type);
        return baseType.IsAssignableFrom(type);
    }

    /// <summary>
    ///     判断当前泛型类型是否可由指定类型的实例填充
    /// </summary>
    /// <param name="genericType">泛型类型</param>
    /// <param name="type">指定类型</param>
    /// <returns></returns>
    public static bool IsGenericAssignableFrom(this Type genericType, Type type)
    {
        //if (!genericType.IsGenericType) throw new ArgumentException("该功能只支持泛型类型的调用，非泛型类型可使用 IsAssignableFrom 方法。");

        var allOthers = new List<Type> {type};
        if (genericType.IsInterface) allOthers.AddRange(type.GetInterfaces());

        foreach (var other in allOthers)
        {
            var cur = other;
            while (cur != null)
            {
                if (cur.IsGenericType) cur = cur.GetGenericTypeDefinition();
                if (cur.IsSubclassOf(genericType) || cur == genericType) return true;
                cur = cur.BaseType;
            }
        }

        return false;
    }

    /// <summary>
    ///     通过类型转换器获取Nullable类型的基础类型
    /// </summary>
    /// <param name="type"> 要处理的类型对象 </param>
    /// <returns> </returns>
    public static Type GetUnNullableType(this Type type)
    {
        if (IsNullableType(type))
        {
            var nullableConverter = new NullableConverter(type);
            return nullableConverter.UnderlyingType;
        }

        return type;
    }


    /// <summary>
    ///     判断是否IEnumerable、ICollection类型
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public static bool IsEnumerable(this Type type)
    {
        return type.IsArray
               || type.GetInterfaces().Any(x => x == typeof(ICollection) || x == typeof(IEnumerable));
    }

    /// <summary>
    ///     从类型成员获取指定Attribute特性
    /// </summary>
    /// <typeparam name="T">Attribute特性类型</typeparam>
    /// <param name="memberInfo">类型类型成员</param>
    /// <param name="inherit">是否从继承中查找</param>
    /// <returns>存在返回第一个，不存在返回null</returns>
    public static T? GetAttribute<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute
    {
        var attributes = memberInfo.GetCustomAttributes(typeof(T), inherit);
        return attributes.FirstOrDefault() as T;
    }

    /// <summary>
    ///     获取类型的Description特性描述信息
    /// </summary>
    /// <param name="type">类型对象</param>
    /// <param name="inherit">是否搜索类型的继承链以查找描述特性</param>
    /// <returns>返回Description特性描述信息，如不存在则返回类型的全名</returns>
    public static string? GetDescription(this Type type, bool inherit = true)
    {
        var desc = type.GetAttribute<DescriptionAttribute>(inherit);
        return desc == null ? type.FullName : desc.Description;
    }

    /// <summary>
    ///     获取成员元数据的Description特性描述信息
    /// </summary>
    /// <param name="member">成员元数据对象</param>
    /// <param name="inherit">是否搜索成员的继承链以查找描述特性</param>
    /// <returns>返回Description特性描述信息，如不存在则返回成员的名称</returns>
    public static string? GetDescription(this MemberInfo member, bool inherit = true)
    {
        var desc = member.GetAttribute<DescriptionAttribute>(inherit);
        if (desc != null) return desc.Description;
        var displayName = member.GetAttribute<DisplayNameAttribute>(inherit);
        if (displayName != null) return displayName.DisplayName;
        var display = member.GetAttribute<DisplayAttribute>(inherit);
        return display != null ? display.Name : member.Name;
    }

    /// <summary>
    ///     从类型成员获取指定Attribute特性
    /// </summary>
    /// <typeparam name="type">Attribute特性类型</typeparam>
    /// <param name="memberInfo">类型类型成员</param>
    /// <param name="inherit">是否从继承中查找</param>
    /// <returns>存在返回第一个，不存在返回null</returns>
    public static Type? GetAttribute(this MemberInfo memberInfo, Type type, bool inherit = true)
    {
        var attributes = memberInfo.GetCustomAttributes(type, inherit);
        return attributes.FirstOrDefault() as Type;
    }

    public static string ToDescription(this MemberInfo member)
    {
        var desc = member.GetCustomAttribute<DescriptionAttribute>();
        if (desc != null) return desc.Description;

        //显示名
        var display = member.GetCustomAttribute<DisplayNameAttribute>();
        return display != null ? display.DisplayName : member.Name;
    }

    /// <summary>
    ///     get TypeCode for specific type
    /// </summary>
    /// <param name="type">type</param>
    /// <returns></returns>
    public static TypeCode GetTypeCode(this Type type)
    {
        return Type.GetTypeCode(type);
    }

    public static bool IsBasicType<T>()
    {
        return typeof(T).IsBasicType();
    }

    public static bool IsBasicType<T>(this T value)
    {
        return value.IsBasicType();
    }

    /// <summary>
    ///     判断type 是否是T的实现
    /// </summary>
    /// <param name="type"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static bool IsAssignableTo<T>(this Type type)
    {
        return typeof(T).IsAssignableFrom(type);
    }

    public static bool IsNonAbstractClass(this Type type, bool publicOnly)
    {
        var typeInfo = type.GetTypeInfo();

        if (typeInfo.IsSpecialName) return false;

        if (typeInfo.IsClass && !typeInfo.IsAbstract)
        {
            if (typeInfo.IsDefined(typeof(CompilerGeneratedAttribute), true)) return false;

            if (publicOnly) return typeInfo.IsPublic || typeInfo.IsNestedPublic;

            return true;
        }

        return false;
    }

    public static IEnumerable<Type> GetBaseTypes(this Type type)
    {
        var typeInfo = type.GetTypeInfo();

        foreach (var implementedInterface in typeInfo.ImplementedInterfaces) yield return implementedInterface;

        var baseType = typeInfo.BaseType;

        while (baseType != null)
        {
            var baseTypeInfo = baseType.GetTypeInfo();

            yield return baseType;

            baseType = baseTypeInfo.BaseType;
        }
    }

    public static bool IsInNamespace(this Type type, string @namespace)
    {
        var typeNamespace = type.Namespace ?? string.Empty;

        if (@namespace.Length > typeNamespace.Length) return false;

        var typeSubNamespace = typeNamespace.Substring(0, @namespace.Length);

        if (typeSubNamespace.Equals(@namespace, StringComparison.Ordinal))
        {
            if (typeNamespace.Length == @namespace.Length)
                //exactly the same
                return true;

            //is a subnamespace?
            return typeNamespace[@namespace.Length] == '.';
        }

        return false;
    }

    public static bool IsInExactNamespace(this Type type, string @namespace)
    {
        return string.Equals(type.Namespace, @namespace, StringComparison.Ordinal);
    }

    public static bool HasAttribute(this Type type, Type attributeType)
    {
        return type.GetTypeInfo().IsDefined(attributeType, true);
    }

    public static bool HasAttribute<T>(this Type type) where T : Attribute
    {
        return type.GetTypeInfo().IsDefined(typeof(T), true);
    }

    public static bool HasAttribute<T>(this Type type, Func<T, bool> predicate) where T : Attribute
    {
        return type.GetTypeInfo().GetCustomAttributes<T>(true).Any(predicate);
    }

    public static bool IsAssignableTo(this Type type, Type otherType)
    {
        var typeInfo = type.GetTypeInfo();
        var otherTypeInfo = otherType.GetTypeInfo();

        if (otherTypeInfo.IsGenericTypeDefinition) return typeInfo.IsAssignableToGenericTypeDefinition(otherTypeInfo);

        return otherTypeInfo.IsAssignableFrom(typeInfo);
    }

    private static bool IsAssignableToGenericTypeDefinition(this TypeInfo typeInfo, TypeInfo genericTypeInfo)
    {
        var interfaceTypes = typeInfo.ImplementedInterfaces.Select(t => t.GetTypeInfo());

        foreach (var interfaceType in interfaceTypes)
            if (interfaceType.IsGenericType)
            {
                var typeDefinitionTypeInfo = interfaceType
                    .GetGenericTypeDefinition()
                    .GetTypeInfo();

                if (typeDefinitionTypeInfo.Equals(genericTypeInfo)) return true;
            }

        if (typeInfo.IsGenericType)
        {
            var typeDefinitionTypeInfo = typeInfo
                .GetGenericTypeDefinition()
                .GetTypeInfo();

            if (typeDefinitionTypeInfo.Equals(genericTypeInfo)) return true;
        }

        var baseTypeInfo = typeInfo.BaseType?.GetTypeInfo();

        if (baseTypeInfo is null) return false;

        return baseTypeInfo.IsAssignableToGenericTypeDefinition(genericTypeInfo);
    }


    private static IEnumerable<Type> GetImplementedInterfacesToMap(TypeInfo typeInfo)
    {
        if (!typeInfo.IsGenericType) return typeInfo.ImplementedInterfaces;

        if (!typeInfo.IsGenericTypeDefinition) return typeInfo.ImplementedInterfaces;

        return FilterMatchingGenericInterfaces(typeInfo);
    }

    private static IEnumerable<Type> FilterMatchingGenericInterfaces(TypeInfo typeInfo)
    {
        var genericTypeParameters = typeInfo.GenericTypeParameters;

        foreach (var current in typeInfo.ImplementedInterfaces)
        {
            var currentTypeInfo = current.GetTypeInfo();

            if (currentTypeInfo.IsGenericType && currentTypeInfo.ContainsGenericParameters
                                              && GenericParametersMatch(genericTypeParameters,
                                                  currentTypeInfo.GenericTypeArguments))
                yield return currentTypeInfo.GetGenericTypeDefinition();
        }
    }

    private static bool GenericParametersMatch(IReadOnlyList<Type> parameters, IReadOnlyList<Type> interfaceArguments)
    {
        if (parameters.Count != interfaceArguments.Count) return false;

        for (var i = 0; i < parameters.Count; i++)
            if (parameters[i] != interfaceArguments[i])
                return false;

        return true;
    }

    //public static string ToFriendlyName(this Type type)
    //{
    //    return TypeNameHelper.GetTypeDisplayName(type, includeGenericParameterNames: true);
    //}

    public static bool IsOpenGeneric(this Type type)
    {
        return type.GetTypeInfo().IsGenericTypeDefinition;
    }

    public static bool HasMatchingGenericArity(this Type interfaceType, TypeInfo typeInfo)
    {
        if (typeInfo.IsGenericType)
        {
            var interfaceTypeInfo = interfaceType.GetTypeInfo();

            if (interfaceTypeInfo.IsGenericType)
            {
                var argumentCount = interfaceType.GenericTypeArguments.Length;
                var parameterCount = typeInfo.GenericTypeParameters.Length;

                return argumentCount == parameterCount;
            }

            return false;
        }

        return true;
    }

    public static Type GetRegistrationType(this Type interfaceType, TypeInfo typeInfo)
    {
        if (typeInfo.IsGenericTypeDefinition)
        {
            var interfaceTypeInfo = interfaceType.GetTypeInfo();

            if (interfaceTypeInfo.IsGenericType) return interfaceType.GetGenericTypeDefinition();
        }

        return interfaceType;
    }

    /// <summary>
    ///     是原始的扩展包括空
    /// </summary>
    /// <param name="type"></param>
    /// <param name="includeEnums"></param>
    /// <returns></returns>
    public static bool IsPrimitiveExtendedIncludingNullable(this Type type, bool includeEnums = false)
    {
        if (IsPrimitiveExtended(type, includeEnums)) return true;

        if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            return IsPrimitiveExtended(type.GenericTypeArguments[0], includeEnums);

        return false;
    }

    private static bool IsPrimitiveExtended(Type type, bool includeEnums)
    {
        if (type.GetTypeInfo().IsPrimitive) return true;

        if (includeEnums && type.GetTypeInfo().IsEnum) return true;

        return type == typeof(string) ||
               type == typeof(decimal) ||
               type == typeof(DateTime) ||
               type == typeof(DateTimeOffset) ||
               type == typeof(TimeSpan) ||
               type == typeof(Guid);
    }


    /// <summary>
    ///     是否可以被实例化出来
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public static bool CanInstanced(this Type type)
    {
        return type.IsClass && !type.IsAbstract;
    }

    /// <summary>
    ///     检测是否是泛型接口的实现类
    /// </summary>
    /// <param name="type"></param>
    /// <param name="target"></param>
    /// <returns></returns>
    public static bool IsImplGenericInterface(this Type type, Type target)
    {
        if (type.IsGenericType(target)) return true;
        return type.GetInterfaces().Any(t => t.IsGenericType(target));
    }

    /// <summary>
    ///     检测是否是只实现、继承了这个泛型
    /// </summary>
    /// <param name="type"></param>
    /// <param name="genericType"></param>
    /// <returns></returns>
    public static bool IsGenericType(this Type type, Type genericType)
    {
        return type.IsGenericType && type.GetGenericTypeDefinition() == genericType;
    }
}